/*
 * XPacket.cpp
 *
 *  Created on: 2009-3-22
 *      Author: gzh
 */

#include "XPacket.h"
#include <stdlib.h>
#include <string.h>

XPacket::slab XPacket::m_slab;

//	导致原有数据失效
char* XPacket::alloc_buf(size_t nDataSize, size_t nHeadRes, size_t nTailRes)
{
	size_t nTotalSize = nDataSize+nHeadRes+nTailRes;
	size_t nOldSize = buf_size();
	if (nOldSize < nTotalSize){
		if (nOldSize > 0)
			m_slab.free_buf(m_pBuf, nOldSize);
		m_pBuf = m_slab.alloc_buf(&nTotalSize);
		if (!m_pBuf){
			printf("alloc_buf: out of memory, alloc size: %d\n", nTotalSize);
			return NULL;
		}
	}
	m_pEnd	= m_pBuf+nTotalSize;
	m_pHead	= m_pBuf+nHeadRes;
	m_pTail	= m_pBuf+nHeadRes+nDataSize;
	return m_pHead;
}

void XPacket::free_buf()
{
	m_slab.free_buf(m_pBuf, buf_size());
	m_pBuf = m_pEnd = m_pHead = m_pTail = NULL;
}

void XPacket::copy_buf(const XPacket& rhs)
{
	int headSize = rhs.m_pHead - rhs.m_pBuf;
	int tailSize = rhs.m_pEnd - rhs.m_pTail;

	char* p = alloc_buf(rhs.data_size(), headSize, tailSize);
	if (!p){
		printf("error: out of memory, alloc size: %d\n", rhs.buf_size());
		return;
	}
	memcpy(p, rhs.data_begin(), rhs.data_size());
}

/**
 *	接合两个数据包，使其成为一个，新的数据包头部保留nHead字节，尾部保留nTail字节空间
 *	@arg  	rhs		接合到本数据包尾部的另一个数据包
 *	@arg  	nHead	新数据包头部需要保留的空间长度
 *	@arg  	nTail	新数据包尾部需要保留的空间长度
 *	@return 错误编号
 */
int XPacket::splice(const XPacket& rhs, size_t nHead, size_t nTail)
{
	size_t lhsBufSize = buf_size();
	size_t lhsDataSize = data_size();
	size_t rhsDataSize = rhs.data_size();
	size_t dataSize = lhsDataSize + rhsDataSize;
	size_t bufSize = nHead+nTail+dataSize;

	if (bufSize <= lhsBufSize){		//已经有足够的空间
		if (lhsDataSize)
			memmove(m_pBuf+nHead, data_begin(), lhsDataSize);
		if (rhsDataSize)
			memcpy(m_pBuf+nHead+lhsDataSize, rhs.data_begin(), rhsDataSize);
		m_pHead = m_pBuf+nHead;
		m_pTail = m_pBuf+nHead+dataSize;
		return err_noerror;
	}
	char* pNewBuf = m_slab.alloc_buf(&bufSize);
	if (!pNewBuf){
		printf("error: out of memory, alloc size: %d\n", bufSize);
		return err_outmemory;
	}
	if (lhsDataSize)
		memcpy(pNewBuf+nHead, data_begin(), lhsDataSize);
	if (rhsDataSize)
		memcpy(pNewBuf+nHead+lhsDataSize, rhs.data_begin(), rhsDataSize);

	m_slab.free_buf(m_pBuf, buf_size());
	m_pBuf	= pNewBuf;
	m_pHead	= pNewBuf+nHead;
	m_pTail	= m_pHead+dataSize;
	m_pEnd	= m_pBuf+bufSize;
	return err_noerror;
}
/*
 *	紧缩存储池，将多余内存返还操作系统
 */
void XPacket::deflate_pool()
{
	m_slab.deflate();
}

char* XPacket::alloc_buf(size_t& cnt)
{
	return m_slab.alloc_buf(&cnt);
}

void XPacket::free_buf(char* p, size_t cnt)
{
	m_slab.free_buf(p, cnt);
}

/*
void XPacket::swap(XPacket& rhs)
{
	::zswap(m_pkType, rhs.m_pkType);
	::zswap(m_pSession, rhs.m_pSession);
	::zswap(m_nSsno, rhs.m_nSsno);
	::zswap(m_nShead, rhs.m_nShead);
	::zswap(m_pHead, rhs.m_pHead);
	::zswap(m_pTail, rhs.m_pTail);
	::zswap(m_pBuf, rhs.m_pBuf);
	::zswap(m_pEnd, rhs.m_pEnd);
	::zswap(m_small_flag, rhs.m_small_flag);
}

void XPacket::swap_data(XPacket& rhs)
{
	::zswap(m_pHead, rhs.m_pHead);
	::zswap(m_pTail, rhs.m_pTail);
	::zswap(m_pBuf, rhs.m_pBuf);
	::zswap(m_pEnd, rhs.m_pEnd);
}
*/

inline size_t align_size(size_t size){
	static size_t sizes[9] = {1024, 1024, 2048, 4096, 4096, 8192, 8192, 8192, 8192};
	int idx = (size+1023) / 1024;
	return idx > 8 ? size : sizes[idx];
}

XPacket::slab::slab()
{
}

XPacket::slab::~slab()
{
}
/*
 *	分配一段内存
 *	@arg  	[in/out]pSize	输入输出参数，表示需要分配的长度和用以返回实际分配的长度
 *	@return 返回所分配的内存块首址
 */
char* XPacket::slab::alloc_buf(size_t* pSize)
{
	assert(pSize);
	*pSize = align_size(*pSize);
	//TODO:从预定义缓冲池中分配
	return (char*)malloc(*pSize);
}
/*
 *	将内存放回缓冲池中
 *	@arg  	pBuf	需释放的内存块首址
 *	@arg  	size	内存块的长度
 */
void XPacket::slab::free_buf(char* pBuf, size_t size)
{
	//UNUSED(size);
	if (pBuf && !size)
		free(pBuf);
}

void XPacket::slab::deflate()
{

}
